iT邦幫忙

2023 iThome 鐵人賽

DAY 2
1
自我挑戰組

複習 JavaScript 核心概念系列 第 2

[Day 02] JavaScript 從解析到執行的過程

  • 分享至 

  • xImage
  •  

本篇我想來談談JavaScript從原始碼到成功執行的過程。在此之前先來看看直譯式語言編譯式語言的概述(節錄自維基百科):

直譯語言(英語:Interpreted language)是一種程式語言類型。這種類型的程式語言,會將程式碼一句一句直接執行,不需要像編譯語言(Compiled language)一樣,經過編譯器先行編譯為機器碼,之後再執行。

編譯語言(英語:Compiled language)是一種程式語言類型,通過編譯器來實作,先將程式碼編譯為機器碼,再加以執行。

我們知道JavaScript是直譯式語言,理論上可能會認為程式碼會由上而下直接執行,若某行程式碼有錯,也會正常運作到該行程式碼才報錯。但事實真的如我們想像的這樣嗎?我們先來看看以下程式碼片段:

console.log('檢查點A');
let myPet cat;
console.log('檢查點B');

我們可以發現第二行很明顯有有錯的,但根據直譯語言由上而下直接執行的特性,應該會先輸出檢查點A然後才報錯。然而當我們查看控制台卻發現根本沒有任何輸出就直接報錯了!

JavaScript 從解析到執行的過程
為什麼會發生這種情況呢?這就要進入我們今天的主題了。


JavaScript運作流程

其實電腦還是無法直接看懂JavaScript程式碼的,仍是需要先透過轉譯器進行解析後才執行,其運作過程通常會經歷以下階段:

1. 語法單元化/詞彙分析 (Tokenizing/Lexical Analysis)

在JavaScript程式碼執行之前,首先需要將原始碼分解為稱為token的小單元。這一過程稱為詞彙分析或單元化。token是程式碼的基本構建塊,如變數名稱、運算符、括號、數字、字符串等。這過程是將程式碼轉換為一個電腦容易理解的結構。

2. 解析並生成抽象結構樹 (Abstract Syntax Tree(AST))

在解析階段,JavaScript的轉譯器會將這些token轉換成稱為AST的抽象語法樹。AST是一個樹狀結構,其中每個節點表示程式碼的一個部分,例如函數聲明、變數賦值、運算式等等。AST的結構使得電腦能夠理解程式碼的語義並執行,例如對於程式碼let x = 10;,AST將包含一個變數聲明節點,它有一個子節點表示賦值操作。

3. 執行

一旦AST構建完成,轉譯器可以遍歷AST並執行其中的程式碼。執行過程涉及變數賦值、運算、函數呼叫、條件判斷等操作,並在適當的時候產生結果或擲出錯誤等等。


我們來看看實際的例子,這裡會用到Esprima線上工具來做說明。
來看看以下程式碼:

let x = 10;

首先針對上述程式碼,轉譯器會先將其拆解成token如下:

[
    {
        "type": "Keyword",
        "value": "let"
    },
    {
        "type": "Identifier",
        "value": "x"
    },
    {
        "type": "Punctuator",
        "value": "="
    },
    {
        "type": "Numeric",
        "value": "10"
    },
    {
        "type": "Punctuator",
        "value": ";"
    }
]

完成第一階段後,接著會將AST解析成類似以下的樹狀結構:

{
  "type": "Program",
  "body": [
    {
      "type": "VariableDeclaration",
      "declarations": [
        {
          "type": "VariableDeclarator",
          "id": {
            "type": "Identifier",
            "name": "x"
          },
          "init": {
            "type": "Literal",
            "value": 10,
            "raw": "10"
          }
        }
      ],
      "kind": "let"
    }
  ],
  "sourceType": "script"
}

最後當以上步驟都完成,就會開始執行我們的程式碼啦。


回到我們一開始給的範例:

console.log('檢查點A');
let myPet cat;
console.log('檢查點B');

大致了解運作過程,我們就不難知道為什麼沒有輸出「檢查點A」了。因為這段程式碼在解析過程中就遇到問題(無法解析"cat"),也就不會有後面的執行階段,自然部會有任何輸出了。

這時可能有人會懷疑JavaScript真的是直譯式語言嗎?
我們再來看另一個例子:

console.log('檢查點A');
let myPet = cat;
console.log('檢查點B');

此時卻會發現跟剛剛的情況不一樣,再報錯之前有輸出"檢查點A"了!

這是因為第二個範例順利通過解析並順利執行了,執行過程中第一行可以順利輸出沒問題,但第二行因為"cat"未定義所以報錯,並不再執行剩下的程式碼。也就是說JS還是有保留直譯式語言的特性喔。

備註: 仍有其他因素會導致程式碼不會依上下行逐行執行的情況,會在之後提到。

結語

今天介紹了JavaScript從解析到執行的過程,會經歷以下階段:

  1. 語法單元化/詞彙分析 (Tokenizing/Lexical Analysis)
  2. 解析並生成抽象結構樹 (Abstract Syntax Tree(AST))
  3. 執行

另外也簡單舉例了解析階段錯誤和執行階段錯誤的差別。
雖然在正式開發上比較不會直接碰到底層運作邏輯,但畢竟這是程式運作的基礎,所以我還是拿出來談一下。
最後跟各位說聲明天見~


上一篇
[Day 01] 前言
下一篇
[Day 03] 宣告關鍵字: var, let, const
系列文
複習 JavaScript 核心概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言